package com.xuecheng.media.config.threadpool;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Component
@ConditionalOnProperty(name = "thread-pool.dynamic.adjust.enabled", havingValue = "true")
public class DynamicThreadPoolAdjuster {

    private final ThreadPoolExecutor executor;                      // 线程池
    private final ThreadPoolAutoConfiguration.ThreadPoolProperties properties;      //线程池的原始配置状态

    // 使用AtomicInteger实现平滑调整
    private final AtomicInteger adjustmentCount = new AtomicInteger(0);     //记录调整次数

    @Value("${thread-pool.dynamic.adjust.interval-ms:60000}")
    private long adjustIntervalMs;                                      //视频负载检测频率

    @Value("${thread-pool.dynamic.adjust.max-change-per-step:2}")
    private int maxChangePerStep;                                       // 单次最大调整次数

    @Autowired
    public DynamicThreadPoolAdjuster(ThreadPoolExecutor executor, ThreadPoolAutoConfiguration.ThreadPoolProperties properties) {
        this.executor = executor;
        this.properties = properties;
    }

    @Scheduled(fixedRateString = "${thread-pool.dynamic.adjust.interval-ms:60000}")
    public void adjustPool() {
        if (executor == null) return;

        // 1. 计算系统负载
        double loadFactor = calculateLoadFactor();

        // 2. 计算新的池大小
        int currentCoreSize = executor.getCorePoolSize();
        int newCoreSize = calculateNewPoolSize(loadFactor, currentCoreSize);
        int newMaxSize = calculateNewMaxSize(newCoreSize);

        // 3. 应用调整（平滑调整）
        applySmoothAdjustment(currentCoreSize, newCoreSize, newMaxSize);

        // 4. 记录调整次数
        adjustmentCount.incrementAndGet();
    }

    //负载计算
    private double calculateLoadFactor() {
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();

        // 更准确获取系统负载（平均1分钟内）
        double cpuLoad = osBean.getSystemLoadAverage();
        int processors = Runtime.getRuntime().availableProcessors();

        // 获取更准确的负载信息
        if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
            com.sun.management.OperatingSystemMXBean sunOsBean =
                    (com.sun.management.OperatingSystemMXBean) osBean;
            cpuLoad = sunOsBean.getSystemCpuLoad();
        }

        // 保护逻辑
        if (cpuLoad < 0) cpuLoad = 0;
        if (processors <= 0) processors = 1;

        return Math.min(cpuLoad / processors, 2.0); // 最大200%
    }

    // 核心计算
    private int calculateNewPoolSize(double loadFactor, int currentSize) {
        int minCoreSize = Math.max(1, properties.getCoreSize() / 2);
        int maxCoreSize = properties.getCoreSize() * 2;

        int change = 0;

        // 过载时增加
        if (loadFactor > 0.85) {
            change = Math.min(maxChangePerStep, maxCoreSize - currentSize);
        }
        // 低负载时减少
        else if (loadFactor < 0.3) {
            change = -Math.min(maxChangePerStep, currentSize - minCoreSize);
        }

        return Math.max(minCoreSize, Math.min(maxCoreSize, currentSize + change));
    }

    // 最大线程数计算
    private int calculateNewMaxSize(int newCoreSize) {
        return Math.max(newCoreSize + 2, (int) (newCoreSize * 1.5));
    }

    // 平滑调整
    private void applySmoothAdjustment(int currentCore, int newCore, int newMax) {
        // 仅当变化需要调整时才操作
        if (currentCore == newCore && executor.getMaximumPoolSize() == newMax) {
            return;
        }

        // 调整顺序很重要：先增大最大池大小，再调整核心池大小
        if (newMax > executor.getMaximumPoolSize()) {
            executor.setMaximumPoolSize(newMax);
        }
        if (newCore != executor.getCorePoolSize()) {
            executor.setCorePoolSize(newCore);
        }
        if (newMax < executor.getMaximumPoolSize()) {
            executor.setMaximumPoolSize(newMax);
        }
    }

    // 调整记录
    public int getAdjustmentCount() {
        return adjustmentCount.get();
    }
}